;; This file is part of GNUnet
;; Copyright (C) 2021 GNUnet e.V.
;;
;; GNUnet is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Affero General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version.
;;
;; GNUnet is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;
;; SPDX-License-Identifier: AGPL-3.0-or-later

;; Small wrapper around guile-gcrypt
(define-library (gnu gnunet crypto)
  (export hash/sha512 hash/sha512!)
  (import (only (gcrypt hash)
		hash-algorithm open-hash-port sha512)
	  (gnu gnunet utils bv-slice)
	  (only (srfi srfi-8)
		receive)
	  (only (guile)
		%make-void-port close-port)
	  (only (ice-9 binary-ports)
		put-bytevector)
	  (only (rnrs base)
		begin lambda define))
  (begin
    ;; TODO: Extend bytevector-hash with offset + length.
    (define (hash-slice/bytevector algorithm slice)
      "Hash the data in the readable bytevector slice @var{slice} and
return a bytevector with the resulting hash."
      (define slice/read (slice/read-only slice))
      (receive (port get-hash) (open-hash-port algorithm)
	(put-bytevector port
			(slice-bv slice/read)
			(slice-offset slice/read)
			(slice-length slice/read))
	(close-port port)
	(get-hash)))

    (define (hash-slice! algorithm slice to)
      "Hash the data in the readable bytevector slice @var{slice} and write the
hash to the bytevector slice @var{to}."
      (slice-copy! (bv-slice/read-write (hash-slice/bytevector algorithm slice))
		   to))

    (define (hash-slice algorithm slice)
      "Hash the data in the readable bytevector slice @var{slice} and return a
fresh readable bytevector slice with the hash."
      (slice/read-only
       (bv-slice/read-write (hash-slice/bytevector algorithm slice))))

    (define (hasher! algorithm)
      (lambda (slice to)
	(hash-slice! algorithm slice to)))

    (define (hasher algorithm)
      (lambda (slice)
	(hash-slice algorithm slice)))

    ;; (hash/sha512! data-to-hash-slice destination-slice) --> (nothing)
    (define hash/sha512! (hasher! (hash-algorithm sha512)))
    (define hash/sha512 (hasher (hash-algorithm sha512)))))
